package org.easy.module.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.easy.common.domain.SysDictDataDO;
import org.easy.common.domain.SysDivisionsDO;
import org.easy.common.domain.SysMailTemplateDO;
import org.easy.common.domain.SysUserDO;
import org.easy.common.generator.SnowflakeIdWorker;
import org.easy.module.mapper.SysDictDataMapper;
import org.easy.module.mapper.SysDivisionsMapper;
import org.easy.module.mapper.SysMailTemplateMapper;
import org.easy.module.mapper.SysUserMapper;
import org.easy.module.service.TestService;
import org.easy.module.service.TestService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 测试service实现类
 *
 * @Author ZhouZhiXin
 * @Date 2022/10/21 15:55
 */
@Slf4j
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    SysDictDataMapper sysDictDataMapper;
    @Autowired
    SysDivisionsMapper sysDivisionsMapper;
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    TestService1 testService1;
    @Autowired
    SysMailTemplateMapper sysMailTemplateMapper;
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Override
    public void testTransactional(SysDictDataDO sysDictDataDO) {
        try {
            testService1.testTransactional(sysDictDataDO);
        } catch (Exception e) {
            testService1.updateData(sysDictDataDO);
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public void updateData(SysDictDataDO sysDictDataDO) {
        sysDictDataDO.setId("7653492343132160");
        sysDictDataDO.setDataDesc("4");
        sysDictDataMapper.updateById(sysDictDataDO);
    }

    @Override
    public void testParallelSearch1() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 1,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
        try {
            CompletableFuture<Long> longCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
                Page<SysDivisionsDO> page1 = new Page<>(1, 10000);
                IPage<SysDivisionsDO> result1 = sysDivisionsMapper.selectPage(page1, new QueryWrapper<>());
                log.info(Thread.currentThread().getName() + " 完成");
                return result1.getSize();
            }, executor);
            CompletableFuture<Long> longCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
                Page<SysDivisionsDO> page2 = new Page<>(10000, 10000);
                IPage<SysDivisionsDO> result2 = sysDivisionsMapper.selectPage(page2, new QueryWrapper<>());
                log.info(Thread.currentThread().getName() + " 完成");
                return result2.getSize();
            }, executor);
            CompletableFuture<Long> longCompletableFuture3 = CompletableFuture.supplyAsync(() -> {
                Page<SysDivisionsDO> page3 = new Page<>(20000, 10000);
                IPage<SysDivisionsDO> result3 = sysDivisionsMapper.selectPage(page3, new QueryWrapper<>());
                log.info(Thread.currentThread().getName() + " 完成");
                return result3.getSize();
            }, executor);
            CompletableFuture.allOf(longCompletableFuture1, longCompletableFuture2, longCompletableFuture3).join();
            log.info(longCompletableFuture1.get() + longCompletableFuture2.get() + longCompletableFuture3.get() +
                    Thread.currentThread().getName());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        } finally {
            executor.shutdown();
        }
    }

    @Override
    public void testParallelSearch2() {
        Page<SysDivisionsDO> page1 = new Page<>(1, 10000);
        IPage<SysDivisionsDO> result1 = sysDivisionsMapper.selectPage(page1, new QueryWrapper<>());
        Page<SysDivisionsDO> page2 = new Page<>(10000, 10000);
        IPage<SysDivisionsDO> result2 = sysDivisionsMapper.selectPage(page2, new QueryWrapper<>());
        Page<SysDivisionsDO> page3 = new Page<>(20000, 10000);
        IPage<SysDivisionsDO> result3 = sysDivisionsMapper.selectPage(page3, new QueryWrapper<>());
        log.info(String.valueOf(result1.getSize() + result2.getSize() + result3.getSize()));
    }

    @Override
    public synchronized void parallelTest() {
        try {
            log.info(Thread.currentThread().getName() + " in");
            TimeUnit.SECONDS.sleep(1);
            log.info(Thread.currentThread().getName() + " out");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public SysUserDO testSqlInjection(String userName) {
        return sysUserMapper.testSqlInjection(userName);
    }

    @Override
    public String testCache() {
        return JSON.toJSONString(sysDivisionsMapper.testCache().size());
    }

    @Override
    public void testInsert() {
        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();

        log.info("------------开始插入数据------------");
        long start = System.currentTimeMillis();
        int sum = 0;
        List<SysMailTemplateDO> list = new ArrayList<>();
        for (int i = 1; i <= 150000; i++) {
            SysMailTemplateDO sysMailTemplateDO = new SysMailTemplateDO();
            sysMailTemplateDO.setId(SnowflakeIdWorker.generateId().toString());
            sysMailTemplateDO.setSubject(String.valueOf(i));
            sysMailTemplateDO.setContent(String.valueOf(i));
            sysMailTemplateDO.setType("邮件");
            sysMailTemplateDO.setCreateBy("system");
            sysMailTemplateDO.setCreateTime(new Date());
            sysMailTemplateDO.setDeleted("0");
            list.add(sysMailTemplateDO);
            if (i % 1000 == 0) {
                defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                TransactionStatus transaction = dataSourceTransactionManager.getTransaction(defaultTransactionDefinition);
                sum += sysMailTemplateMapper.insertTest(list);
                log.info("成功写入" + sum + "条数据");
                dataSourceTransactionManager.commit(transaction);
                list.clear();
            }
        }
        log.info("------------插入数据完成------------");
        long end = System.currentTimeMillis();
        log.info("耗时" + (end - start) + "ms");
    }

    // 阈值
    private static final Integer QPS = 2;
    // 时间窗口（毫秒）
    private static final long TIME_WINDOWS = 3000;
    // 计数器
    private static final AtomicInteger REQ_COUNT = new AtomicInteger();

    private static long START_TIME = System.currentTimeMillis();

    public synchronized static boolean tryAcquire() {
        if ((System.currentTimeMillis() - START_TIME) > TIME_WINDOWS) {
            REQ_COUNT.set(0);
            START_TIME = System.currentTimeMillis();
        }
        return REQ_COUNT.incrementAndGet() <= QPS;
    }

    @Override
    public void testLimiting() {
        LocalTime now = LocalTime.now();
        if (!tryAcquire()) {
            System.out.println(now + " 被限流");
        } else {
            System.out.println(now + " 做点什么");
        }
    }
}
